package org.redmagic.client.prototype;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.redmagic.client.api.Location;
import org.redmagic.client.api.LocationFactory;
import org.redmagic.client.utils.DocumentUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

public class RMConfiguration {

	private static final Log LOG = LogFactory.getLog(RMConfiguration.class);
	
	private final ImmutableMap<String, LocationFactory> locationFactories;
	private final ImmutableList<Location> locations;
	private final ConcurrentLinkedQueue<Location> locationQueue;

	public RMConfiguration(Map<String, LocationFactory> factories, RMFileResolver fileResolver) {
		checkNotNull(factories, "factories");
		checkNotNull(fileResolver, "fileResolver");
		this.locationFactories = ImmutableMap.copyOf(factories);
		this.locations = parseLocations(fileResolver.getResolvedFileContentsAsDocument());
		this.locationQueue = new ConcurrentLinkedQueue<Location>(this.locations);
	}
	
	private ImmutableList<Location> parseLocations(Document configurationFileDocument) {
		
		ImmutableList.Builder<Location> locations = new ImmutableList.Builder<Location>();
		
		for (Element locationElement : DocumentUtils.getChildElements(configurationFileDocument.getDocumentElement())) {
			
			try {
				
				String locationFactoryName = locationElement.getNodeName() + "Factory";
				LOG.debug("Looking for factory bean: " + locationFactoryName);
				LocationFactory locationFactory = this.locationFactories.get(locationFactoryName);

				if (locationFactory == null) {
					throw new RuntimeException("Unable to find location factory: " + locationFactoryName);
				} else {
					locations.add(locationFactory.createLocation(locationElement));
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		return locations.build();
	}
	
	public Optional<Location> getNextLocation() {
		return Optional.fromNullable(this.locationQueue.poll());
	}
	
	public void finished (Properties resolvedProperties) {
		for (Location location : this.locations) {
			location.finished(resolvedProperties);
		}
	}
}